﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace RouteConvertTool
{

    // 航点数据模型
    public class Waypoint
    {
        public int No { get; set; }
        public Coordinates Coordinates { get; set; }
        public double Heading { get; set; }
        public string TurnMode { get; set; } = "Auto";
        public double GimbalPitch { get; set; }
        public List<WaypointAction> Actions { get; set; } = new List<WaypointAction>();
        public string ComponentType { get; set; }
        public string ComponentLon { get; set; }
        public string ComponentLat { get; set; }
        public string ComponentAlt { get; set; }
        public string phase { get; set; }
        /// <summary>
        /// 线路名
        /// </summary>
        public string routeName { get; set; }
        /// <summary>
        /// 杆塔号
        /// </summary>
        public string towerNo { get; set; }
    }

    public class Coordinates
    {
        public double Longitude { get; set; }
        public double Latitude { get; set; }
        public double Altitude { get; set; }
    }

    public class WaypointAction
    {
        public string ActionType { get; set; }
        public string Param { get; set; }
        public string Label { get; set; }
    }

    public class KmlGenerator
    {
        public static void GenerateWaypointKML(string filePath, List<Waypoint> waypoints,double autoFlightSpeed = 5, double altitude = 20.0)
        {
            XmlDocument doc = new XmlDocument();
            XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
            doc.AppendChild(declaration);

            // 创建根元素
            XmlElement kml = doc.CreateElement("kml");
            kml.SetAttribute("xmlns", "http://www.opengis.net/kml/2.2");
            doc.AppendChild(kml);

            // 创建Document元素
            XmlElement document = doc.CreateElement("Document");
            kml.AppendChild(document);

            // 添加任务信息
            AddMissionInfo(doc, document);

            // 创建航点文件夹
            XmlElement folder = CreateWaypointsFolder(doc, waypoints);
            document.AppendChild(folder);

            // 创建航线
            XmlElement wayline = CreateWayline(doc, waypoints,autoFlightSpeed, altitude);
            document.AppendChild(wayline);

            //doc.Save(filePath);
            // 使用StreamWriter保存为无BOM的UTF-8编码
            Encoding utf8 = new UTF8Encoding(false);
            using (StreamWriter writer = new StreamWriter(filePath, false, utf8))
            {
                doc.Save(writer);
            }
        }

        private static void AddMissionInfo(XmlDocument doc, XmlElement parent)
        {
            XmlElement name = doc.CreateElement("name");
            name.InnerText = "航线任务";
            parent.AppendChild(name);

            XmlElement open = doc.CreateElement("open");
            open.InnerText = "1";
            parent.AppendChild(open);

            XmlElement extendedData = doc.CreateElement("ExtendedData");
            extendedData.SetAttribute("xmlns:mis", "www.dji.com");
            AddMisElement(doc, extendedData, "type", "Waypoint");
            parent.AppendChild(extendedData);
        }

        private static XmlElement CreateWaypointsFolder(XmlDocument doc, List<Waypoint> waypoints)
        {
            XmlElement folder = doc.CreateElement("Folder");

            XmlElement folderName = doc.CreateElement("name");
            folderName.InnerText = "waypoints";
            folder.AppendChild(folderName);

            XmlElement description = doc.CreateElement("description");
            description.InnerText = "Waypoints in the Mission";
            folder.AppendChild(description);

            // 添加各个航点
            for (int i = 0; i < waypoints.Count; i++)
            {
                folder.AppendChild(CreatePlacemark(doc, waypoints[i], i + 1));
            }

            return folder;
        }


        private static void AddCoordinatesElement(XmlDocument doc, XmlElement parent, Coordinates coordinates)
        {
            // 将 Coordinates 对象转换为字符串
            string coordinatesString = $"{coordinates.Longitude:F14},{coordinates.Latitude:F14},{coordinates.Altitude:F14}";

            XmlElement coordElement = doc.CreateElement("coordinates");
            coordElement.InnerText = coordinatesString;
            parent.AppendChild(coordElement);
        }

        private static XmlElement CreatePlacemark(XmlDocument doc, Waypoint wp, int index)
        {
            XmlElement placemark = doc.CreateElement("Placemark");

            // 基本信息
            AddTextElement(doc, placemark, "name", $"Waypoint{index}");
            //AddTextElement(doc, placemark, "name", $"Waypoint{index} {wp.No}");
            AddTextElement(doc, placemark, "visibility", "1");
            AddTextElement(doc, placemark, "description", "Waypoint");

            // 扩展数据
            XmlElement extendedData = doc.CreateElement("ExtendedData");
            extendedData.SetAttribute("xmlns:mis", "www.dji.com");

            AddMisElement(doc, extendedData, "heading", wp.Heading.ToString());
            AddMisElement(doc, extendedData, "turnMode", wp.TurnMode);
            AddMisElement(doc, extendedData, "gimbalPitch", wp.GimbalPitch.ToString("0.0"));
            AddMisElement(doc, extendedData, "useWaylineAltitude", "false");

            // 添加其他扩展数据（根据实际需要扩展）
            foreach (var action in wp.Actions)
            {
                XmlElement actionElement = doc.CreateElement("mis:actions", "www.dji.com");
                actionElement.SetAttribute("param", action.Param);
                actionElement.SetAttribute("label", action.Label);
                actionElement.InnerText = action.ActionType;
                extendedData.AppendChild(actionElement);
            }

            placemark.AppendChild(extendedData);

            // 坐标点
            XmlElement point = doc.CreateElement("Point");
            AddTextElement(doc, point, "altitudeMode", "absolute");
            AddCoordinatesElement(doc, point, wp.Coordinates); // 传递 Coordinates 对象
            placemark.AppendChild(point);


            if (!String.IsNullOrEmpty(wp.ComponentType)) 
            {
                AddTextElement(doc, placemark, "componentType", wp.ComponentType);
            }
            if (!String.IsNullOrEmpty(wp.ComponentLon))
            {
                AddTextElement(doc, placemark, "componentLon", wp.ComponentLon);
            }
            if (!String.IsNullOrEmpty(wp.ComponentLat))
            {
                AddTextElement(doc, placemark, "componentLat", wp.ComponentLat);
            }
            if (!String.IsNullOrEmpty(wp.ComponentAlt))
            {
                AddTextElement(doc, placemark, "componentAlt", wp.ComponentAlt);
            }
            if (!String.IsNullOrEmpty(wp.phase))
            {
                AddTextElement(doc, placemark, "phase", wp.phase);
            }
            if (!String.IsNullOrEmpty(wp.routeName))
            {
                AddTextElement(doc, placemark, "routeName", wp.routeName);
            }
            if (!String.IsNullOrEmpty(wp.towerNo))
            {
                AddTextElement(doc, placemark, "towerNo", wp.towerNo);
            }

            return placemark;
        }

        private static XNamespace ns = "http://www.opengis.net/kml/2.2";
        private static XNamespace mis = "www.dji.com";

   

        private static XmlElement CreateWayline(XmlDocument doc, List<Waypoint> waypoints, double autoFlightSpeed = 5.0,double altitude = 20.0)
        {
            XmlElement placemark = doc.CreateElement("Placemark");
            AddTextElement(doc, placemark, "name", "Wayline");
            AddTextElement(doc, placemark, "description", "Wayline");
            AddTextElement(doc, placemark, "visibility", "1");

            // 扩展数据
            XmlElement extendedData = doc.CreateElement("ExtendedData");
            extendedData.SetAttribute("xmlns:mis", "www.dji.com");
            AddMisElement(doc, extendedData, "altitude", altitude.ToString());
            AddMisElement(doc, extendedData, "autoFlightSpeed", autoFlightSpeed.ToString());
            AddMisElement(doc, extendedData, "actionOnFinish", "GoHome");
            AddMisElement(doc, extendedData, "headingMode", "UsePointSetting");
            AddMisElement(doc, extendedData, "gimbalPitchMode", "UsePointSetting");


            // 添加无人机信息
            XmlElement droneInfo = doc.CreateElement("mis", "droneInfo", "www.dji.com");
            AddMisElement(doc, droneInfo, "droneType", "P4R");

            XmlElement droneHeight = doc.CreateElement("mis", "droneHeight", "www.dji.com");
            AddMisElement(doc, droneHeight, "useAbsolute", "true");
            AddMisElement(doc, droneHeight, "hasTakeoffHeight", "false");
            AddMisElement(doc, droneHeight, "takeoffHeight", "0.0");

            droneInfo.AppendChild(droneHeight);
            extendedData.AppendChild(droneInfo);

            placemark.AppendChild(extendedData);

            // 航线坐标
            XmlElement lineString = doc.CreateElement("LineString");
            AddTextElement(doc, lineString, "tessellate", "1");
            AddTextElement(doc, lineString, "altitudeMode", "absolute");

            string coordinates = string.Join(" ", waypoints.ConvertAll(w =>
                $"{w.Coordinates.Longitude:F14},{w.Coordinates.Latitude:F14},{w.Coordinates.Altitude:F14}"));

            AddCoordinatesElement(doc, lineString, coordinates);
            placemark.AppendChild(lineString);

            return placemark;
        }

        // 辅助方法
        private static void AddTextElement(XmlDocument doc, XmlElement parent, string name, string value)
        {
            XmlElement element = doc.CreateElement(name);
            element.InnerText = value;
            parent.AppendChild(element);
        }

        private static void AddMisElement(XmlDocument doc, XmlElement parent, string name, string value)
        {
            XmlElement element = doc.CreateElement("mis", name, "www.dji.com");
            element.InnerText = value;
            parent.AppendChild(element);
        }

        private static void AddCoordinatesElement(XmlDocument doc, XmlElement parent, string coordinates)
        {
            XmlElement coordElement = doc.CreateElement("coordinates");
            coordElement.InnerText = coordinates;
            parent.AppendChild(coordElement);
        }
    }

}
